package ua.yandex.shad.tempseries;

public class TemperatureSeriesAnalysis {

    private final double[] temperatureSeries;
    public static final double MAX_IMPOSSIBLE_TEMPERATURE = 10e100;
    public static final double MIN_POSSIBLE_TEMPERATURE = -273;

    public TemperatureSeriesAnalysis(final double[] temperatureSeries)
            throws IllegalTemperatureValueException {
        checkTemperaturePossibilityInSeries(temperatureSeries);
        this.temperatureSeries = new double[temperatureSeries.length];
        System.arraycopy(temperatureSeries, 0, this.temperatureSeries, 0,
                temperatureSeries.length);
    }

    public double calcAverageTemp() {
        double sum = 0;
        if (IsEmptyTemperatureSeries(temperatureSeries)) {
            return sum;
        }
        for (double temperature : temperatureSeries) {
            sum += temperature;
        }
        return sum / temperatureSeries.length;
    }

    public double calcTempDeviation() {
        if (IsEmptyTemperatureSeries(temperatureSeries)) {
            return 0;
        }
        double sumOfSquares = 0;
        for (double temperature : temperatureSeries) {
            sumOfSquares += Math.pow(temperature, 2);
        }
        double deviation = (sumOfSquares
                - Math.pow(calcAverageTemp(), 2) * temperatureSeries.length)
                / temperatureSeries.length;
        return deviation;
    }

    public double findTempClosestToZero() {

        return findTempClosestToValue(0);
    }

    public double findTempClosestToValue(final double tempValue) {
        if (IsEmptyTemperatureSeries(temperatureSeries)) {
            return 0;
        }
        double closestToValue = MAX_IMPOSSIBLE_TEMPERATURE;
        for (double temperature : temperatureSeries) {
            if (Math.abs(closestToValue - tempValue)
                    > Math.abs(temperature - tempValue)) {
                closestToValue = temperature;
            } else {
                if (Math.abs(closestToValue - tempValue)
                        == Math.abs(temperature - tempValue)
                        && Math.signum(temperature * closestToValue) == -1) {
                    closestToValue = closestToValue
                            < temperature ? temperature : closestToValue;
                }
            }
        }
        return closestToValue;
    }

    public double[] findTempsLessThen(final double tempValue) {
        if (IsEmptyTemperatureSeries(temperatureSeries)) {
            return null;
        }
        int tempsLessThenValueSize = 0;
        for (double temperature : temperatureSeries) {
            if (temperature < tempValue) {
                tempsLessThenValueSize++;
            }
        }
        double[] tempsLessThenValue = new double[tempsLessThenValueSize];
        int index = 0;
        for (double temperature : temperatureSeries) {
            if (temperature < tempValue) {
                tempsLessThenValue[index] = temperature;
                index++;
            }
        }
        return tempsLessThenValue;
    }

    public double[] findTempsGreaterThen(final double tempValue) {
        if (IsEmptyTemperatureSeries(temperatureSeries)) {
            return null;
        }
        int tempsLessThenValueSize = 0;
        for (double temperature : temperatureSeries) {
            if (temperature > tempValue) {
                tempsLessThenValueSize++;
            }
        }
        double[] tempsLessThenValue = new double[tempsLessThenValueSize];
        int index = 0;
        for (double temperature : temperatureSeries) {
            if (temperature > tempValue) {
                tempsLessThenValue[index] = temperature;
                index++;
            }
        }
        return tempsLessThenValue;
    }

    public double[] forecatsTemp(final double tempValue) {
        return new double[]{};
    }

    private void checkTemperaturePossibility(final double temperature)
            throws IllegalTemperatureValueException {
        if (temperature < MIN_POSSIBLE_TEMPERATURE) {
            throw new IllegalTemperatureValueException();
        }
    }

    private void checkTemperaturePossibilityInSeries(
            final double[] temperatureSeries)
            throws IllegalTemperatureValueException {
        for (double temperature : temperatureSeries) {
            checkTemperaturePossibility(temperature);
        }
    }

    private boolean IsEmptyTemperatureSeries(
            final double[] temperatureSeries) {
        return temperatureSeries.length == 0;
    }

}

